﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Cody.CsvProcessor
{
    public class CsvHelper : IDisposable
    {
        private bool isHaveTitle = true;
        /// <summary>
        /// 第一行是否包含标题
        /// </summary>
        public bool IsHaveTitle
        {
            private get
            {
                return this.isHaveTitle;
            }
            set
            {
                this.isHaveTitle = value;
            }
        }

        private int columns = 0;
        public int Columns
        {
            get
            {
                return this.columns;
            }
            set
            {
                if (value == 0)
                {
                    throw new ArgumentOutOfRangeException("Columns", "列宽不能为0");
                }
                this.columns = value;
            }
        }

        private string csvFullPath;
        public string CsvFullPath
        {
            private get
            {
                return this.csvFullPath;
            }
            set
            {
                if (!File.Exists(value))
                {
                    throw new FileNotFoundException("文件不存在!", this.CsvFullPath);
                }
                this.csvFullPath = value;
            }
        }

        public bool EndOfFile { get; private set; }

        private Encoding encoding = Encoding.UTF8;
        public Encoding Encoding
        {
            get
            {
                return this.encoding;
            }
            set
            {
                this.encoding = value;
            }
        }

        private StreamReader FileReader = null;
        private string[] SourceLines = null;
        private bool isUseString = false;
        private int LineIndex = 0;

        public int Lenght
        {
            get
            {
                return this.SourceLines.Length;
            }
        }

        public CsvHelper()
        {
            this.FileReader = new StreamReader(this.CsvFullPath, this.Encoding);
            if (this.IsHaveTitle)
            {
                this.FileReader.ReadLine();
                this.EndOfFile = this.FileReader.EndOfStream;
            }
        }

        public CsvHelper(string file, bool isHaveTitle, int columns)
        {
            this.CsvFullPath = file;
            this.IsHaveTitle = isHaveTitle;
            this.Columns = columns;

            this.FileReader = new StreamReader(this.CsvFullPath, this.Encoding);
            if (this.IsHaveTitle)
            {
                this.FileReader.ReadLine();
                this.EndOfFile = this.FileReader.EndOfStream;
            }
        }

        public CsvHelper(string sourceString, int columns, bool isHaveTitle)
        {
            if (string.IsNullOrEmpty(sourceString))
            {
                throw new ArgumentNullException("sourceString", "字符串不能为空!");
            }
            this.SourceLines = sourceString.Split(new char[] { '\r', '\n' });
            this.IsHaveTitle = isHaveTitle;
            this.Columns = columns;
            this.isUseString = true;

            if (this.IsHaveTitle)
            {
                LineIndex = 1;
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.FileReader != null)
                {
                    this.FileReader.Close();
                    this.FileReader = null;
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public List<string> ReadRow()
        {
            string line = null;
            if (this.isUseString)
            {
                line = this.SourceLines[this.LineIndex];
                this.EndOfFile = (this.LineIndex == this.SourceLines.Length - 1);
                this.LineIndex++;
            }
            else
            {
                line = this.FileReader.ReadLine();
                this.EndOfFile = this.FileReader.EndOfStream;
            }
            if (string.IsNullOrEmpty(line))
            {
                return null;
            }

            List<string> row = new List<string>();
            string[] array = line.Split(',');
            if (array.Length == this.Columns)
            {
                foreach (string s in array)
                {
                    row.Add(s);
                }
            }
            else if (array.Length < this.columns)
            {
                throw new Exception("Error!\r\n数据列丢失.\r\n" + line);
            }
            else //array.Lenght > this.columns
            {
                for (int i = 0; i < array.Length; i++)
                {
                    if (array[i].StartsWith("\""))
                    {
                        string temp = array[i];
                        if (temp.EndsWith("\"") && temp.ToList().Count(a => { return a == '"'; }) % 2 == 0)
                        {
                            row.Add(temp.Trim());
                            continue;
                        }

                        if (i == array.Length - 1)
                        {
                            row.Add(temp);
                        }
                        for (int j = i + 1; j < array.Length; j++)
                        {
                            temp += "," + array[j];
                            var l = array[j].ToList();
                            if ((l.Count == 1 && l[0] == '"') ||
                                (l.Count > 1 && l[l.Count - 1] == '"' && l[l.Count - 2] != '"'))
                            {
                                i = j;
                                row.Add(temp.TrimEnd(','));
                                break;
                            }
                        }
                    }
                    else
                    {
                        row.Add(array[i]);
                    }
                }
            }
            return row;
        }
    }
}